它是C中唯一可用于#define
多if
语句操作的结构,后面加一个分号,并且仍然在语句中使用.一个例子可能有帮助:
#define FOO(x) foo(x); bar(x) if (condition) FOO(x); else // syntax error here ...;
即使使用大括号也无济于事:
#define FOO(x) { foo(x); bar(x); }
在if
语句中使用它将要求您省略分号,这是违反直觉的:
if (condition) FOO(x) else ...
如果你这样定义FOO:
#define FOO(x) do { foo(x); bar(x); } while (0)
那么以下语法是正确的:
if (condition) FOO(x); else ....
@LarryF:问题是,如果您正在编写供其他人使用的头文件,则无法选择其他人如何使用您的宏.为了避免对用户造成意外的意外,您必须使用上述技术使您的宏行为与任何其他C语句的行为一样. (45认同)
如果编码正确的话,我仍然认为这是UGLY和SLOPPY编码,并且可以避免.这可以追溯到一些常识C规则,总是在你的IF语句中使用卷曲,即使在IF之后只有一个操作.这应该是标准做法,IMVHO ...... (13认同)
不会`#define FOO(x)if(true){foo(x); 杆(X); } else void(0)`即使它更丑陋也可以工作? (5认同)
@ user10607:是的,如果你的宏扩展是*表达式*的列表,那么这是有效的.但是,如果你想在扩展中包含一个`if`或`while`,那么这个技巧也行不通. (4认同)
但是`#define FOO(x)foo(x),bar(x)`如何使用逗号代替分号.如果不这样做,这不会很好吗? (2认同)
这个答案多么令人惊讶 (2认同)
@Max好的,如果您仍然对自己的问题有疑问,请提出新问题,而不是使用评论.谢谢. (2认同)
Jere.Jones.. 105
这是一种简化错误检查并避免深层嵌套if的方法.例如:
do { // do something if (error) { break; } // do something else if (error) { break; } // etc.. } while (0);
或者使用`goto`.不,严重的说,`if(错误)转到错误;`和一个`错误:......`接近结尾似乎是一个更清洁的版本,对我来说完成同样的事情. (63认同)
呃,将其纳入方法,并使用早期回报. (14认同)
或者......只需使用do {} while(0). (13认同)
@WChargin:您链接的文章中的"goto fail"代码也会因"中断"而失败.有人刚刚在那里复制了一条线.这不是goto的错. (5认同)
@NiccoloM."被授予,goto不是错误,这实际上让它更有趣" (4认同)
Martin v. Lö.. 76
它有助于将多个语句分组到一个语句中,因此类似函数的宏实际上可以用作函数.假设你有
#define FOO(n) foo(n);bar(n)
你也是
void foobar(int n) { if (n) FOO(n); }
然后这扩大到
void foobar(int n) { if (n) foo(n);bar(n); }
请注意,第二个调用(bar(n))不再是if语句的一部分.
将两者都包装到do {} while(0)中,也可以在if语句中使用宏.
它是C中唯一可用于#define
多if
语句操作的结构,后面加一个分号,并且仍然在语句中使用.一个例子可能有帮助:
#define FOO(x) foo(x); bar(x) if (condition) FOO(x); else // syntax error here ...;
即使使用大括号也无济于事:
#define FOO(x) { foo(x); bar(x); }
在if
语句中使用它将要求您省略分号,这是违反直觉的:
if (condition) FOO(x) else ...
如果你这样定义FOO:
#define FOO(x) do { foo(x); bar(x); } while (0)
那么以下语法是正确的:
if (condition) FOO(x); else ....
这是一种简化错误检查并避免深层嵌套if的方法.例如:
do { // do something if (error) { break; } // do something else if (error) { break; } // etc.. } while (0);
它有助于将多个语句分组到一个语句中,因此类似函数的宏实际上可以用作函数.假设你有
#define FOO(n) foo(n);bar(n)
你也是
void foobar(int n) { if (n) FOO(n); }
然后这扩大到
void foobar(int n) { if (n) foo(n);bar(n); }
请注意,第二个调用(bar(n))不再是if语句的一部分.
将两者都包装到do {} while(0)中,也可以在if语句中使用宏.
有趣的是,要注意以下情况:在做{}而(0)循环不会为你工作:
如果你想要一个返回值的类函数宏,那么你将需要一个语句表达式:({stmt; stmt;})而不是do {} while(0):
#include#define log_to_string1(str, fmt, arg...) \ do { \ sprintf(str, "%s: " fmt, "myprog", ##arg); \ } while (0) #define log_to_string2(str, fmt, arg...) \ ({ \ sprintf(str, "%s: " fmt, "myprog", ##arg); \ }) int main() { char buf[1000]; int n = 0; log_to_string1(buf, "%s\n", "No assignment, OK"); n += log_to_string1(buf + n, "%s\n", "NOT OK: gcc: error: expected expression before 'do'"); n += log_to_string2(buf + n, "%s\n", "This fixes it"); n += log_to_string2(buf + n, "%s\n", "Assignment worked!"); printf("%s", buf); return 0; }